/**************************************************************************
 * Copyright (C) 2017-2017  Unisound
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 **************************************************************************
 *
 * Description : uni_iot.c
 * Author      : wufangfang@unisound.com
 * Date        : 2019.09.11
 *
 **************************************************************************/

#include "uni_iot.h"
#include "interrupt.h"
#include "uni_hal_mailbox.h"
#include "DrvUART010.h"
#include "gpio.h"
#include "timer.h"
#include "ftsdc021.h"
#include "dma.h"
#include "uni_pinmux.h"

int uni_pthread_create(uni_pthread_t *thread, struct thread_param *para,
                            start_routine task_func, void* arg) {
  if (para->th_priority < OS_PRIORITY_REALTIME) {
    para->th_priority = OS_PRIORITY_REALTIME;
  }
  if (para->th_priority > OS_PRIORITY_LOW) {
    para->th_priority = OS_PRIORITY_LOW;
  }
  *thread = rt_thread_create(para->task_name, task_func, arg,
                             para->stack_size, para->th_priority, 5);
  if (RT_NULL == *thread) {
    return -1;
  }
  rt_thread_startup(*thread);
  return 0;
}

int uni_pthread_destroy(uni_pthread_t th) {
  if (RT_NULL == th) {
    return rt_thread_delete(rt_thread_self());
  }
  return rt_thread_delete(th);
}

int uni_sem_init(uni_sem_t *sem, unsigned int value) {
  if (NULL == sem) {
    return -1;
  }
  *sem = rt_sem_create("sem", value, RT_IPC_FLAG_FIFO);
  if (NULL == *sem) {
    return -1;
  }
  return 0;
}

int uni_pthread_mutex_init(uni_mutex_t *mutex) {
  if (NULL == mutex) {
    return -1;
  }
  *mutex = rt_mutex_create("mutex", RT_IPC_FLAG_FIFO);
  if (NULL == *mutex) {
    return -1;
  }
  return 0;
}

int _internal_init(void) {
  int value;

  WRITE(0x41000100 + 0x104 , 0x00000000); // ext_addr
  WRITE(0x41000100 + 0x100 , 0xffffffff); // ext_write

  WRITE(0x41000100 + 0x104 , 0x00000010); // ext_addr
  WRITE(0x41000100 + 0x100 , 0x00000000); // ext_write
   
//sdio pinmux
  //sdio pinmux
  write_mreg32(0x41000104, 0x04);
  value = (0x01 << 9) | (0x01 << 12) | (0x01 << 15) | (0x01 << 18) | (0x01 << 21) | (0x01 << 24);
  printf("AFTER 111  value is 0x%x\r\n",value);
  write_mreg32(0x41000100, value);

  write_mreg32(0x41000104, 0x04);
  value = read_mreg32(0x41000100);

  printf("AFTER 222  value is 0x%x\r\n",value);

  return 0;
}

void uni_start_hifi(void) {
#if !HIFI_MOCK_TEST
  int addr;
  int value;
  /* start HIFI5 */
  addr = 0x41000818;
  value = READ(addr);
  value &= ~(1 << 25);
  value &= ~(1 << 26);
  value &= ~(1 << 28);
  WRITE(addr, value);
#endif
}

int uni_system_init(void) {
  uni_pinmux_init();

  uni_gpio_irq_init();

  fLib_DMAInit();

  /* init mailbox */
  return sys_hal_mailbox_init();
  //return 0;
}

int uni_system_final(void) {
  return 0;
}

#define CONFIG_SYS_CACHELINE_SIZE 8

int _check_cache_range(unsigned long start, unsigned long stop) {
  int ok = 1;
  if (start & (CONFIG_SYS_CACHELINE_SIZE - 1)) {
    ok = 0;
  }
  if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1)) {
    ok = 0;
  }
  return ok;
}

extern void _invalidate_dcache_range(void* start);
extern void _flush_dcache_range_1(void* start);
extern void _flush_dcache_range_2(void);
void invalidate_dcache_range(unsigned long start, unsigned long stop) {
  if (!_check_cache_range(start, stop)) {
    return;
  }
  while (start < stop) {
    //asm volatile("mcr p15, 0, %0, c7, c6, 1\n" : : "r"(start));
    _invalidate_dcache_range((void *)start);
    start += CONFIG_SYS_CACHELINE_SIZE;
  }
}

void flush_dcache_range(unsigned long start, unsigned long stop) {
  if (!_check_cache_range(start, stop)) {
    return;
  }
  while (start < stop) {
    //asm volatile("mcr p15, 0, %0, c7, c14, 1\n" : : "r"(start));
    _flush_dcache_range_1((void *)start);
    start += CONFIG_SYS_CACHELINE_SIZE;
  }
  //asm volatile("mcr p15, 0, %0, c7, c10, 4\n" : : "r"(0));
  _flush_dcache_range_2();
}

